# encoding: utf-8
import os;
import sys;
#import xml.dom.minidom;

DEVMAIN = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]),"../../../../"));
sys.path.append(os.path.abspath(os.path.join(DEVMAIN,"Code/Tools/utils")))
#print(sys.path)

import axlib.xml;
import axlib.output;
import codecs;
import subprocess;

DEFAULT_CONFIG = {
    "input_filename" : "../meta_xml/csproto.xml",
    "output_filename" : "../csproto_process.h",
    "tdr_exe" : "../../../Server/Tools/tsf4g/tdr.exe",
    "tdr_h_filename" : "../csproto.h",
    "tdr_c_filename" : "../csproto.c",
    "tdr_bin_filename" : "../csproto.tdr",
    };

OUTPUT_ENCODING = "mbcs";

    
def gen( cfg ):
    global OUTPUT_ENCODING;
    print( "open meta file[%s]... " % cfg["input_filename"] );
    #doc = xml.dom.minidom.parse( cfg["input_filename"] );
    info = {};
    doc = axlib.xml.xmlParse( cfg["input_filename"], info = info );
    if "file_encoding" in info:
        OUTPUT_ENCODING = info["file_encoding"];
    genProcessH( doc, cfg["output_filename"] );
    genPlayerExtensions( doc );
    genTDR( cfg["tdr_exe"], cfg["input_filename"], cfg["tdr_h_filename"], 
            cfg["tdr_c_filename"], cfg["tdr_bin_filename"] );
            
            
def genProcessH( meta_doc, output_filename ):
    print( "generationg process header file[%s]... " % output_filename );
    fd = axlib.output.OutputFile.open( output_filename, encoding="utf_8_sig", ignore_CRLF = True );
    #print( "writing... 1" );
    #fd.write( codecs.BOM_UTF8 );
    fd.write( "/**************************************/\n" );
    fd.write( "/*this file is auto generate by script*/\n" );
    fd.write( "/**************************************/\n" );

    #print( "writing... 2" );
    fd.write( "#ifndef MH_PROCESS_ENTRY\n" );
    fd.write( "#define MH_PROCESS_ENTRY(id,type,name,desc)\n" );
    fd.write( "#endif  //MH_PROCESS_ENTRY\n" );
    

    root = meta_doc.documentElement;
    for node in root.getElementsByTagName("union"):
        #print( node, node.getAttribute("name") );
        if node.hasAttribute("name") and node.getAttribute("name") == 'CSPkgBody':
            for child in node.getElementsByTagName("entry"):
                entry_name = child.getAttribute("name");  
                entry_type = child.getAttribute("type");  
                entry_id = child.getAttribute("id");  
                entry_desc = child.getAttribute("desc");

                #print( "writing... 3 %s" % entry_name );
                fd.write( "MH_PROCESS_ENTRY(%s,%s,%s,\"%s\")\n" % (entry_id,entry_type,entry_name,entry_desc) );
               
            break;
    #print( "writing... 4" );
    fd.write( "/*EOF*/\n" );
    #print( "closing" );
    fd.close();
    print( "generate process header file[%s]... done." % output_filename );
    return;
    
    
def genTDR( exe_fn, in_fn, h_fn, c_fn, bin_fn ):
    #"%TOOLS_HOME%/tdr.exe" -H -O %CS_PROTOCOL_H% %CS_XML_FILES%
    #"%TOOLS_HOME%/tdr.exe" -C -o %CS_PROTOCOL_C% %CS_XML_FILES%
    #"%TOOLS_HOME%/tdr.exe" -B -o %CS_PROTOCOL_TDR% %CS_XML_FILES%
    if not os.path.isdir("tmp"):
        os.mkdir("tmp");
    print(str(subprocess.Popen( [exe_fn, "-H", "-O", "tmp", in_fn ], stdout=subprocess.PIPE ).communicate()[0], "mbcs" ) );
    axlib.output.UpdateIfChanged( "tmp/" + os.path.splitext(os.path.basename(in_fn))[0] + ".h", h_fn, True );
    #axlib.output.UpdateIfChanged( "tmp/" + c_fn, c_fn, True );
    print(str(subprocess.Popen( [exe_fn, "-C", "-o", "tmp/" + os.path.basename(c_fn), in_fn ], stdout=subprocess.PIPE ).communicate()[0], "mbcs" ) );
    axlib.output.UpdateIfChanged( "tmp/" + os.path.basename(c_fn), c_fn, True );
    print(str(subprocess.Popen( [exe_fn, "-B", "-o", "tmp/" + os.path.basename(bin_fn), in_fn ], stdout=subprocess.PIPE ).communicate()[0], "mbcs" ) );
    axlib.output.UpdateIfChanged( "tmp/" + os.path.basename(bin_fn), bin_fn, True );


def genPlayerExtensions( doc ):
    COMMON_EXT_DIR = os.path.abspath(os.path.join(DEVMAIN,"Code/Common/CommonLib/PlayerExtension"));
    print( "COMMON_EXT_DIR=%s" % COMMON_EXT_DIR );


    otherinfoproto_xml = axlib.xml.xmlParse( os.path.abspath(os.path.join(DEVMAIN,"Code/Common/Protocols/packetproto_xml/otherinfoproto.xml")) );

    def findNode(root,tagName,attrname,attrvalue):
        for node in root.getElementsByTagName(tagName):
            if node.hasAttribute(attrname) and attrvalue == node.getAttribute(attrname):
                return node;
        return None;
    
    def makeCamel(s):
        return "".join( [ x[0:1].upper()+x[1:].lower() for x in s.split("_")] );
    
    CTYPE_LOOKUP = {
        "int"       : { "ctype" : "int32_t",    "prefix" : "i" },
        "uint16"    : { "ctype" : "uint16_t",   "prefix" : "w" },
        "int8"      : { "ctype" : "int8_t",     "prefix" : "ch" },
        "uint8"     : { "ctype" : "uint8_t",    "prefix" : "b" },
    };
    def getCName( name, type_name, count):
        if not type_name in CTYPE_LOOKUP:
            name = "st" + name;
        else:
            name = CTYPE_LOOKUP[type_name]["prefix"] + name;
        if count:
            name = "a" + name;
        return name;
    
    def lowerFirstChar(s):
        if len(s) > 0:
            return s[0].lower() + s[1:];
        else:
            return "";
            
    
    nodePlayerExtTypeEnum = findNode( doc, "macrosgroup", "name", "CS_PLAYER_EXT_TYPE" );
    if not nodePlayerExtTypeEnum:
        return;
    nodePlayerExtReqUnion = findNode( doc, "union", "name", "CSPlayerExtRequestData" );
    nodePlayerExtNtfUnion = findNode( doc, "union", "name", "CSPlayerExtNotifyData" );
    nodePlayerInit = findNode(doc, "struct", "name", "CSPlayerInitInfo");
    nodeOtherInfoPacket = findNode(otherinfoproto_xml, "struct", "name", "OtherInfoPacket");
    class CType:
        def __init__(self,root):
            for attr in root.attributes:
                setattr( self, attr.name, attr.value );
                pass;
            self.entries = {};
            for child in root.childNodes:
                entry = CType(child);
                self.entries[entry.name] = entry;
                pass;
            pass;
    class Entry:
        def __init__( self, root ):
            self.name = root.getAttribute("name");
            self.type = root.getAttribute("type");
            self.desc = root.hasAttribute("desc") and root.getAttribute("desc") or "";
            self.globalPredefine = [];
            if findNode(doc,"struct","name",self.type):
                self.globalPredefine.append("struct tag" + self.type + ";");

            pass;
        pass;
    class RequestEntry( Entry ):
        def __init__( self, root ):
            Entry.__init__( self, root );
            self.id = root.getAttribute("id");
            self.entries = [];
            class Param(Entry):
                def __init__( self, root ):
                    Entry.__init__( self, root );
                    pass;
                pass;
                
            #self.globalPredefine = [];
            for node in findNode(doc,"struct","name",self.type).getElementsByTagName("entry"):
                entry = Param(node);
                self.entries.append(entry);
                self.globalPredefine += entry.globalPredefine;
            pass;
        def gen_1( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("entry." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += (
                """
	///	%(entry.desc)s
protected:	void _SendRequest_%(entry.name)s( const tag%(entry.type)s& request );
private:	virtual void _OnRequest_%(entry.name)s( const tag%(entry.type)s& request ){};
protected:	void _SendResult_%(entry.name)s( int iResultCode, const tag%(entry.type)s& request );
private:	virtual void _OnResult_%(entry.name)s( int iResultCode, const tag%(entry.type)s& request ){};
"""
                % args );
            out["PlayerExtensionBase.cpp"] += ( """
void %(ext.classname)s::_SendRequest_%(entry.name)s( const tag%(entry.type)s& request )
{
	tagCSPlayerExtRequest request_ext;
	request_ext.chExtType = GetExtensionType();
	request_ext.stRequest.st%(request.name)s.iRequestType = %(entry.id)s;
	request_ext.stRequest.st%(request.name)s.st%(request.union_name)s.st%(entry.name)s = request;
	_SendRequest( request_ext );
}
void %(ext.classname)s::_SendResult_%(entry.name)s( int iResultCode, const struct tag%(entry.type)s& request )
{
	tagCSPlayerExtResult result_ext;
	result_ext.chExtType = GetExtensionType();
	result_ext.iResultCode = iResultCode;
	result_ext.stRequest.st%(request.name)s.iRequestType = %(entry.id)s;
	result_ext.stRequest.st%(request.name)s.st%(request.union_name)s.st%(entry.name)s = request;
	_SendResult( result_ext );
}
""" % args );
            pass;
        def gen_case_result( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("entry." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.cpp"] += ( """
	case %(entry.id)s:
		_OnResult_%(entry.name)s( result.iResultCode, result.stRequest.st%(request.name)s.stRequest.st%(entry.name)s );
		break;
""" % args );
            pass;
        
        def gen_case_request( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("entry." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.cpp"] += ( """
	case %(entry.id)s:
		_OnRequest_%(entry.name)s( request.stRequest.st%(request.name)s.stRequest.st%(entry.name)s );
		break;
""" % args );
            pass;
            
            
        pass;
    class Request:
        def __init__(self,ext,root):
            self.ext = ext;
            self.name = root.getAttribute("name");
            self.type = root.getAttribute("type");
            nodeReqStruct = findNode(doc,"struct","name",self.type);
            node = findNode(nodeReqStruct,"entry","name","RequestType");
            self.enum_name = node.getAttribute("bindmacrosgroup");
            node = findNode(nodeReqStruct,"entry","select","RequestType");
            self.union_name = node.getAttribute("name");
            self.union_type = node.getAttribute("type");
            self.entries = [];
            
            self.globalPredefine = [];
            for node in findNode(doc,"union","name",self.union_type).getElementsByTagName("entry"):
                entry = RequestEntry(node);
                self.entries.append(entry);
                #print(entry.globalPredefine)
                self.globalPredefine += entry.globalPredefine;
                pass;
            pass;
        def gen( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("request." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += """
private:
	virtual void _OnFrame_PlayerExtRequest( const tagCSPlayerExtRequest& request );
	virtual void _OnFrame_PlayerExtResult( const tagCSPlayerExtResult& result );
""";
            for entry in self.entries:
                entry.gen_1(out,args);
                pass;

            #OnFrame_PlayerExtRequest                
            out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnFrame_PlayerExtRequest( const tagCSPlayerExtRequest& request )
{
	if ( request.chExtType != GetExtensionType() )
		return;
	switch( request.stRequest.st%(request.name)s.iRequestType )
	{
	""" % args;
            for entry in self.entries:
                entry.gen_case_request(out,args);
            out["PlayerExtensionBase.cpp"] += """
	}
}
""" % args;
            #OnFrame_PlayerExtResult                
            out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnFrame_PlayerExtResult( const tagCSPlayerExtResult& result )
{
	if ( result.chExtType != GetExtensionType() )
		return;
	switch( result.stRequest.st%(request.name)s.iRequestType )
	{
	""" % args;
            for entry in self.entries:
                entry.gen_case_result(out,args);
            out["PlayerExtensionBase.cpp"] += """
	}
}
""" % args;
            pass;
        pass;
    class NotifyEntry( Entry ):
        def __init__( self, root ):
            Entry.__init__( self, root );
            self.id = root.getAttribute("id");
            self.entries = [];
            class Param(Entry):
                def __init__( self, root ):
                    Entry.__init__( self, root );
                    pass;
                pass;


            #self.globalPredefine = [];
            for node in findNode(doc,"struct","name",self.type).getElementsByTagName("entry"):
                entry = Param(node);
                self.entries.append(entry);
                self.globalPredefine += entry.globalPredefine;
            pass;
        def gen_1( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("entry." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += (
                """
	///	%(entry.desc)s
protected:	void _SendNotify_%(entry.name)s( const tag%(entry.type)s& notify );
private:	virtual void _OnNotify_%(entry.name)s( const tag%(entry.type)s& notify ){};
"""
                % args );
            out["PlayerExtensionBase.cpp"] += ( """
void %(ext.classname)s::_SendNotify_%(entry.name)s( const tag%(entry.type)s& notify )
{
	tagCSPlayerExtNotify notify_ext;
	notify_ext.chExtType = GetExtensionType();
	notify_ext.stNotify.st%(notify.name)s.iNotifyType = %(entry.id)s;
	notify_ext.stNotify.st%(notify.name)s.st%(notify.union_name)s.st%(entry.name)s = notify;
	_SendNotify( notify_ext );
}
""" % args );
            pass;
        def gen_case_notify( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("entry." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.cpp"] += ( """
	case %(entry.id)s:
		_OnNotify_%(entry.name)s( notify.stNotify.st%(notify.name)s.stNotify.st%(entry.name)s );
		break;
""" % args );
            pass;
        
            
            
        pass;
    class Notify:
        def __init__(self,ext,root):
            self.ext = ext;
            self.name = root.getAttribute("name");
            self.type = root.getAttribute("type");
            nodeNtfStruct = findNode(doc,"struct","name",self.type);
            #print(self.type);
            node = findNode(nodeNtfStruct,"entry","name","NotifyType");
            self.enum_name = node.getAttribute("bindmacrosgroup");
            node = findNode(nodeNtfStruct,"entry","select","NotifyType");
            self.union_name = node.getAttribute("name");
            self.union_type = node.getAttribute("type");
            self.entries = [];
            self.globalPredefine = [];
            for node in findNode(doc,"union","name",self.union_type).getElementsByTagName("entry"):
                entry = NotifyEntry(node);
                self.entries.append(entry);
                self.globalPredefine += entry.globalPredefine;
                pass;
            pass;
        def gen( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("notify." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += """
private:
	virtual void _OnFrame_PlayerExtNotify( const tagCSPlayerExtNotify& notify );
""";
            for entry in self.entries:
                entry.gen_1(out,args);
                pass;

            #OnFrame_PlayerExtRequest                
            out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnFrame_PlayerExtNotify( const tagCSPlayerExtNotify& notify )
{
	if ( notify.chExtType != GetExtensionType() )
		return;
	switch( notify.stNotify.st%(notify.name)s.iNotifyType )
	{
	""" % args;
            for entry in self.entries:
                entry.gen_case_notify(out,args);
            out["PlayerExtensionBase.cpp"] += """
	}
}
""" % args;
            pass;
        pass;

    class InitData:
        def __init__(self, name):
            #<entry name="GuideSteps"      type="CSGuideStep"    count="CS_MAX_GUIDE_STEPS"        refer="GuideStepCount"        desc="新手引导完成的步骤"        version="1" />
            node = findNode(nodePlayerInit, "entry", "name", name);
            self.name = node.hasAttribute("name") and node.getAttribute("name") or None;
            self.type = node.hasAttribute("type") and node.getAttribute("type") or None;
            self.count = node.hasAttribute("count") and node.getAttribute("count") or None;
            self.refer = node.hasAttribute("refer") and node.getAttribute("refer") or None;
            if self.refer:
                node = findNode(nodePlayerInit, "entry", "name", self.refer);
                self.refer_name = node.hasAttribute("name") and node.getAttribute("name") or None;
                self.refer_type = node.hasAttribute("type") and node.getAttribute("type") or None;
                self.refer_cname = getCName(self.refer_name, self.refer_type, None);
            
            self.cname = getCName(self.name,self.type,self.count);
            
            self.globalPredefine = [];
            if findNode(doc,"struct","name",self.type):
                self.globalPredefine.append("struct tag" + self.type + ";");
               
            pass;
        def gen( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("init_data." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += """
public:
    virtual void _OnPlayerReadInfo( const tagCSPlayerInitInfo& stInitInfo );
    virtual void _OnPlayerWriteInfo( tagCSPlayerInitInfo& stInitInfo );
private:""" % args;
            if self.count:
                out["PlayerExtensionBase.h"] += """
    virtual void _LoadPlayerInitData( const tag%(init_data.type)s* ast%(init_data.name)s, size_t count ) = 0;""" % args;
                if self.refer:
                    out["PlayerExtensionBase.h"] += """
    virtual void _SavePlayerInitData( tag%(init_data.type)s* ast%(init_data.name)s, const size_t max_count, size_t& count ) = 0;""" % args;
                    out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadInfo( const tagCSPlayerInitInfo& stInitInfo )
{
    _LoadPlayerInitData( stInitInfo.%(init_data.cname)s, stInitInfo.%(init_data.refer_cname)s );
}
void %(ext.classname)s::_OnPlayerWriteInfo( tagCSPlayerInitInfo& stInitInfo )
{
    size_t count = 0;
    _SavePlayerInitData( stInitInfo.%(init_data.cname)s, MH_COUNT_OF_ARRAY(stInitInfo.%(init_data.cname)s), count );
    MH_ASSERT( count <= MH_COUNT_OF_ARRAY(stInitInfo.%(init_data.cname)s) );
    stInitInfo.%(init_data.refer_cname)s = min( count, MH_COUNT_OF_ARRAY(stInitInfo.%(init_data.cname)s) );
}
                    """ % args;
                else:
                    out["PlayerExtensionBase.h"] += """
    virtual void _SavePlayerInitData( tag%(init_data.type)s* ast%(init_data.name)s, const size_t max_count ) = 0;
                    """ % args;
                    out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadInfo( const tagCSPlayerInitInfo& stInitInfo )
{
    _LoadPlayerInitData( stInitInfo.%(init_data.cname)s, %(init_data.count)s );
}
void %(ext.classname)s::_OnPlayerWriteInfo( tagCSPlayerInitInfo& stInitInfo )
{
    _SavePlayerInitData( stInitInfo.%(init_data.cname)s, MH_COUNT_OF_ARRAY(stInitInfo.%(init_data.cname)s) );
}
                    """ % args;
                    
                    
            else:
                out["PlayerExtensionBase.h"] += """
    virtual void _LoadPlayerInitData( const tag%(init_data.type)s& rst%(init_data.name)s ) = 0;
    virtual void _SavePlayerInitData( tag%(init_data.type)s& rst%(init_data.name)s ) = 0;
                """ % args;
                out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadInfo( const tagCSPlayerInitInfo& stInitInfo )
{
    _LoadPlayerInitData( stInitInfo.%(init_data.name)s );
}
void %(ext.classname)s::_OnPlayerWriteInfo( tagCSPlayerInitInfo& stInitInfo )
{
    _SavePlayerInitData( stInitInfo.%(init_data.cname)s );
}
                """ % args;
        pass;


    class OtherData:
        def __init__(self, name):
            #print(name)
            node = findNode(nodeOtherInfoPacket, "entry", "name", name);
            #print(node.attributes.items())
            self.name = node.hasAttribute("name") and node.getAttribute("name") or None;
            self.type = node.hasAttribute("type") and node.getAttribute("type") or None;
            self.count = node.hasAttribute("count") and node.getAttribute("count") or None;
            self.refer = node.hasAttribute("refer") and node.getAttribute("refer") or None;
            if self.refer:
                node = findNode(nodeOtherInfoPacket, "entry", "name", self.refer);
                self.refer_name = node.hasAttribute("name") and node.getAttribute("name") or None;
                self.refer_type = node.hasAttribute("type") and node.getAttribute("type") or None;
                self.refer_cname = lowerFirstChar(self.refer_name);
            
            self.cname = lowerFirstChar(self.name);
            
            self.packprotoPredefine = [];
            if findNode(otherinfoproto_xml,"struct","name",self.type):
                self.packprotoPredefine.append("class " + self.type + ";");
            
                
            pass;
        def gen( self, out, in_args ):
            args = dict( [ x for x in in_args.items() ]
                         + [ ("other_data." + n, getattr(self,n) ) for n in dir(self)] );
            out["PlayerExtensionBase.h"] += """
public:
    virtual void _OnPlayerReadOtherInfo( const packproto::OtherInfoPacket& stOtherInfo );
    virtual void _OnPlayerWriteOtherInfo( packproto::OtherInfoPacket& stOtherInfo );
private:""" % args;
            if self.count:
                out["PlayerExtensionBase.h"] += """
    virtual void _LoadPlayerOtherData( const packproto::%(other_data.type)s* %(other_data.name)s, size_t count ) = 0;""" % args;
                if self.refer:
                    out["PlayerExtensionBase.h"] += """
    virtual void _SavePlayerOtherData( packproto::%(other_data.type)s* %(other_data.name)s, const size_t max_count, size_t& count ) = 0;""" % args;
                    out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadOtherInfo( const packproto::OtherInfoPacket& stOtherInfo )
{
    _LoadPlayerOtherData( stOtherInfo.%(other_data.cname)s, stOtherInfo.%(other_data.refer_cname)s );
}
void %(ext.classname)s::_OnPlayerWriteOtherInfo( packproto::OtherInfoPacket& stOtherInfo )
{
    size_t count = 0;
    _SavePlayerOtherData( stOtherInfo.%(other_data.cname)s, MH_COUNT_OF_ARRAY(stOtherInfo.%(other_data.cname)s), count );
    MH_ASSERT( count <= MH_COUNT_OF_ARRAY(stOtherInfo.%(other_data.cname)s) );
    stOtherInfo.%(other_data.refer_cname)s = min( count, MH_COUNT_OF_ARRAY(stOtherInfo.%(other_data.cname)s) );
}
                    """ % args;
                else:
                    out["PlayerExtensionBase.h"] += """
    virtual void _SavePlayerOtherData( packproto::%(other_data.type)s* %(other_data.name)s, const size_t max_count ) = 0;
                    """ % args;
                    out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadOtherInfo( packproto::OtherInfoPacket& stOtherInfo )
{
    _LoadPlayerOtherData( stOtherInfo.%(other_data.cname)s, %(other_data.count)s );
}
void %(ext.classname)s::_OnPlayerWriteOtherInfo( packproto::OtherInfoPacket& stOtherInfo )
{
    _SavePlayerOtherData( stOtherInfo.%(other_data.cname)s, MH_COUNT_OF_ARRAY(stOtherInfo.%(other_data.cname)s) );
}
                    """ % args;
                    
                    
            else:
                out["PlayerExtensionBase.h"] += """
    virtual void _LoadPlayerOtherData( const struct tag%(other_data.type)s& rst%(other_data.name)s ) = 0;
    virtual void _SavePlayerOtherData( struct tag%(other_data.type)s& rst%(other_data.name)s ) = 0;
                """ % args;
                out["PlayerExtensionBase.cpp"] += """
void %(ext.classname)s::_OnPlayerReadOtherInfo( const packproto::OtherInfoPacket& stOtherInfo )
{
    _LoadPlayerOtherData( stOtherInfo.%(other_data.name)s );
}
void %(ext.classname)s::_OnPlayerWriteOtherInfo( packproto::OtherInfoPacket& stOtherInfo )
{
    _SavePlayerOtherData( stOtherInfo.%(other_data.cname)s );
}
                """ % args;
        pass;
    
    class PlayerExt:
        def __init__(self,root,desc):
            self.root = root;
            self.name = root.getAttribute("name");
            self.value = root.getAttribute("value");
            self.classname = desc["base_class"];
            self.server_class = "server_class" in desc and desc["server_class"] or None;
            self.client_class = "client_class" in desc and desc["client_class"] or None;
            self.local_class = "local_class" in desc and OtherData(desc["local_class"]) or None;
            self.init_data = "init_data" in desc and InitData(desc["init_data"]) or None;
            self.other_data = "other_data" in desc and OtherData(desc["other_data"]) or None;
            node = findNode(nodePlayerExtReqUnion,'entry',"id",self.name);
            self.request = node and Request(self,node) or None;
            node = findNode(nodePlayerExtNtfUnion,'entry',"id",self.name);
            self.notify = node and Notify(self,node) or None;
            
            self.globalPredefine = set();
            self.packprotoPredefine = set();
            
            if self.request and self.request.globalPredefine:
                self.globalPredefine |= set( e for e in self.request.globalPredefine );
            if self.notify and self.notify.globalPredefine:
                self.globalPredefine |= set( e for e in self.notify.globalPredefine );
            
            if self.init_data:
                self.globalPredefine |= set( e for e in self.init_data.globalPredefine );
                
            if self.other_data:
                self.packprotoPredefine |= set( e for e in self.other_data.packprotoPredefine );
            pass;
                        
        def gen(self,out):
            args = dict( [ ('ext.'+n, getattr(self,n) ) for n in dir(self)] );
            
            out["PlayerExtensionBase.h"] += "\n"+"/"*75+"\n//\t%(ext.classname)s\n" % args;
            for d in self.globalPredefine:
                out["PlayerExtensionBase.h"] += d + "\n";
            if len(self.packprotoPredefine)>0:
                out["PlayerExtensionBase.h"] += "namespace packproto\n{\n";
                for d in self.packprotoPredefine:
                    out["PlayerExtensionBase.h"] += "\t" + d + "\n";
                out["PlayerExtensionBase.h"] += "}\n";

            out["PlayerExtensionBase.h"] += """
class %(ext.classname)s : public CPlayerExtension
{
public:
	static bool _GlobalInitExtension( EPlayerExtensionType eType );
	static void _GlobalFiniExtension( EPlayerExtensionType eType );
public:
	%(ext.classname)s( CLogicPlayer& owner );
	virtual ~%(ext.classname)s( void );
public:
	static const EPlayerExtensionType E_EXT_TYPE = %(ext.ext_enum_name)s; 
	virtual EPlayerExtensionType GetExtensionType( void ) const
	{
		return E_EXT_TYPE;
	}
	""" % args;
                

            out["PlayerExtensionBase.cpp"] += (
"""
//////////////////////////////////////////////////////////////////////////
//	%(ext.classname)s
%(ext.classname)s::%(ext.classname)s( CLogicPlayer& owner )
	:	CPlayerExtension(owner)
{
}
%(ext.classname)s::~%(ext.classname)s( void )
{
}
bool %(ext.classname)s::_GlobalInitExtension( EPlayerExtensionType eType )
{
	MH_ASSERT_RETURN_R( CPlayerExtension::_GlobalInitExtension(eType), false );
	return true;
}
void %(ext.classname)s::_GlobalFiniExtension( EPlayerExtensionType eType )
{
	CPlayerExtension::_GlobalInitExtension(eType);
}
	""" % args );


            out["PlayerExtensionBase_Client_Impl.h"] += (
"""
//////////////////////////////////////////////////////////////////////////
//	%(ext.classname)s
	""" % args );
            out["PlayerExtensionBase_Server_Impl.h"] += (
"""
//////////////////////////////////////////////////////////////////////////
//	%(ext.classname)s
	""" % args );

            if self.request:
                self.request.gen(out,args);
            if self.notify:
                self.notify.gen(out,args);
            if self.init_data:
                self.init_data.gen(out,args);
            if self.other_data:
                self.other_data.gen(out,args);

            out["PlayerExtensionBase.h"] += """
};// %(ext.classname)s
	""" % args;

            pass;
        pass;

    out = {};
    out["PlayerExtensionDef.h"] = """
#ifndef _PLAYEREXTENSIONDEF_H_
#define _PLAYEREXTENSIONDEF_H_
///	扩展类型
///	初始化顺序将是按照枚举顺序进行
enum EPlayerExtensionType
{
""";
    out["PlayerExtensionBase.h"] = """
#ifndef _PLAYEREXTENSIONBASE_H_
#define _PLAYEREXTENSIONBASE_H_

#include "PlayerExtension.h"

""";
    out["PlayerExtensionBase.cpp"] = """
#include <Protocols/csproto.h>
#include <Protocols/PacketCode/otherinfoproto.h>
#include <UtilityInterface/MHCommonDef.h>
#include "PlayerExtensionBase.h"

""";
    out["PlayerExtensionBase_Client_Impl.h"] = """
#ifndef _PLAYEREXTENSIONBASE_CLIENT_IMPL_H_
#define _PLAYEREXTENSIONBASE_CLIENT_IMPL_H_

#include <Protocols/csproto.h>

#include "PlayerExtensionBase.h"

""";

    out["PlayerExtensionBase_Server_Impl.h"] = """
#ifndef _PLAYEREXTENSIONBASE_SERVER_IMPL_H_
#define _PLAYEREXTENSIONBASE_SERVER_IMPL_H_

#include <Protocols/csproto.h>

#include "PlayerExtensionBase.h"

""";

    out["PlayerExtension_Proc.h"] = """
#ifndef PROC_PLAYER_EXT_BEGIN
#define PROC_PLAYER_EXT_BEGIN(ext)
#endif	//PROC_PLAYER_EXT_BEGIN

#ifndef PROC_PLAYER_EXT_END
#define PROC_PLAYER_EXT_END(ext)
#endif	//PROC_PLAYER_EXT_END


//#ifndef PROC_PLAYER_EXT_CLIENT_CLASS
//#define PROC_PLAYER_EXT_CLIENT_CLASS(ext,client_class)
//#endif	//PROC_PLAYER_EXT_CLIENT_CLASS

//#ifndef PROC_PLAYER_EXT_CLIENT_LOCAL_CLASS
//#define PROC_PLAYER_EXT_CLIENT_LOCAL_CLASS(ext,client_local_class)
//#endif	//PROC_PLAYER_EXT_CLIENT_LOCAL_CLASS

//#ifndef PROC_PLAYER_EXT_SERVER_CLASS
//#define PROC_PLAYER_EXT_SERVER_CLASS(ext,server_class)
//#endif	//PROC_PLAYER_EXT_SERVER_CLASS

""";

    exts = [];
    ext_count = 0;
    for node in nodePlayerExtTypeEnum.getElementsByTagName("macro"):
        name = node.getAttribute("name");
        friend_name = makeCamel(name[len("CS_PLAYER_EXT"):]);
        ext_enum_name = "ePlayerExtensionType_" + friend_name;
        ext_enum_value = int(node.getAttribute("value"));
        ext_count = max(ext_count, ext_enum_value + 1 );
        desc = dict( [tuple(x) for x in [ x.split("=") for x in node.getAttribute("desc").split(";") ] if len(x) >= 2 ] );
        #print(desc);
        if "base_class" in desc:
            ext = PlayerExt(node,desc);
            setattr(ext,"friend_name",friend_name);
            setattr(ext,"ext_enum_name",ext_enum_name);
            setattr(ext,"ext_enum_value",ext_enum_value);
            exts.append(ext);
            
        
        args = { "ext_enum_value" : ext_enum_value,
            "ext_enum_name" : ext_enum_name,
            "desc" : node.getAttribute("desc").split(";")[0],
        }
        out["PlayerExtensionDef.h"] += """
	/// %(desc)s
	%(ext_enum_name)s = %(ext_enum_value)d,
""" % args;
        out["PlayerExtension_Proc.h"] += """
PROC_PLAYER_EXT_BEGIN(%(ext_enum_name)s)
//PROC_PLAYER_EXT_CLIENT_CLASS(%(ext_enum_name)s,CCliPlayerInteract)
//PROC_PLAYER_EXT_CLIENT_LOCAL_CLASS(%(ext_enum_name)s,CCliLocalPlayerInteract)
//PROC_PLAYER_EXT_SERVER_CLASS(%(ext_enum_name)s,CSvrPlayerInteract)
PROC_PLAYER_EXT_END(%(ext_enum_name)s)
""" % args     
        pass;
    for ext in exts:
        ext.gen(out);

    out["PlayerExtensionDef.h"] += """
	ePlayerExtensionType_Count = %(ext_count)d
};

#endif	//_PLAYEREXTENSIONDEF_H_
""" % { "ext_count" : ext_count };
    out["PlayerExtensionBase.h"] += """
#endif	//_PLAYEREXTENSIONBASE_H_
""";
    out["PlayerExtensionBase_Client_Impl.h"] += """
#endif	//_PLAYEREXTENSIONBASE_CLIENT_IMPL_H_
""";
    out["PlayerExtensionBase_Server_Impl.h"] += """
#endif	//_PLAYEREXTENSIONBASE_SERVER_IMPL_H_
""";
    out["PlayerExtension_Proc.h"] += """
#undef	PROC_PLAYER_EXT_BEGIN 
#undef	PROC_PLAYER_EXT_END 
//#undef	PROC_PLAYER_EXT_CLIENT_CLASS 
//#undef	PROC_PLAYER_EXT_CLIENT_LOCAL_CLASS 
//#undef	PROC_PLAYER_EXT_SERVER_CLASS 
""";
    for (filename,v) in out.items():
        filepath = os.path.join(COMMON_EXT_DIR,filename);
        print( "generating player extension file[%s]... " % filename );
        fd = axlib.output.OutputFile.open( filepath,
                                           encoding = OUTPUT_ENCODING,
                                           ignore_CRLF = True );
        fd.write(v);
        fd.close();
    pass;



if __name__ == "__main__":
    cfg = DEFAULT_CONFIG.copy();
    #for arg_index in range( 0, len(sys.argv) ):
    #    argv = sys.argv[arg_index];
    #    print(argv, argv[0:2]);
    #    #if argv[0:2]
    if len( sys.argv ) >= 2:
        cfg["input_filename"] = os.path.abspath(sys.argv[1]);
    if len( sys.argv ) >= 3:
        cfg["output_filename"] = os.path.abspath(sys.argv[2]);
    if len( sys.argv ) >= 4:
        cfg["tdr_exe"] = os.path.abspath(sys.argv[3]);
    if len( sys.argv ) >= 5:
        cfg["tdr_h_filename"] = os.path.abspath(sys.argv[4]);
    if len( sys.argv ) >= 6:
        cfg["tdr_c_filename"] = os.path.abspath(sys.argv[5]);
    if len( sys.argv ) >= 7:
        cfg["tdr_bin_filename"] = os.path.abspath(sys.argv[6]);
    gen(cfg);


